package com.bxait.toymail.auth.server.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.bxait.com.constant.AuthServerConstant;
import com.bxait.com.exception.BizCodeEnum;
import com.bxait.com.exception.MemberSocialUserEnum;
import com.bxait.com.utils.HttpUtils;
import com.bxait.com.utils.R;
import com.bxait.toymail.auth.server.feign.MemberFeignService;
import com.bxait.toymail.auth.server.feign.ThirdPartFeignService;
import com.bxait.toymail.auth.server.utils.ConstantWxUtils;
import com.bxait.toymail.auth.server.utils.HttpClientUtils;
import com.bxait.com.vo.member.MemberRespVo;
import com.bxait.com.vo.member.SocialUser;
import com.bxait.com.vo.member.WeiBoSocialUser;
import com.bxait.com.vo.member.WeiXinSocialUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/*
@description: 用户认证的controller
@ClassName AuthController
@author Chen
@create 2023-04-20 17:26
@Version 1.0
*/
@Slf4j
@Controller
public class AuthController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ThirdPartFeignService thirdPartFeignService;


    @Resource
    MemberFeignService memberFeignService;


    /*
     * @param phone
     * @==============History===============<br/>
     * @Description // 发送验证码,给指定手机号
     * @Date 2023/4/20 2023/4/20
     * @Author < a href="2277411582@qq.com">chen</ a>
     * @return
     */
    @ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendCode(@RequestParam("phone") String phone){
        // 1.防止接口重刷,在redis中获取数据,当前数据有就提示60秒后再试
        String redisGetCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
        if(!StringUtils.isEmpty(redisGetCode)){
            long nowTime = System.currentTimeMillis();
            Long redisTime = null;
            try {
                redisTime = Long.valueOf(redisGetCode.split("_")[1]);
                // 60秒内不能重复提交
                if(redisTime - nowTime < 60000){
                    return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
                }
            }catch (Exception e){
                log.error("---------类型强转失败---------");
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }

        }

        // 2.随机生成6位数字
        Random random = new Random();
        String code = String.valueOf(random.nextInt(900000) + 100000);
        String redisSetCode = code + "_" + System.currentTimeMillis();

        // 3.设置redis缓存验证码，防止同一个phone在60秒内再次发送验证码
        stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone,redisSetCode,10, TimeUnit.MINUTES);
        thirdPartFeignService.sendCode(phone,code);
        return R.ok();
    }


    /*
     * @param code
     * @param session
     * @param servletResponse
     * @param request
     * @==============History===============<br/>
     * @Description //   处理微博社交登录的回调地址,这块实现的逻辑是在前端直接放了一个超链接直接跳到了微博的登录页,这是在处理微博登录成功的回调方法
     * @Date 2023/4/21 2023/4/21
     * @Author < a href="2277411582@qq.com">chen</ a>
     * @return java.lang.String
     */
    @GetMapping("/oauth2.0/weibo/success")
    public String weibo(@RequestParam("code") String code,
                        HttpSession session,
                        HttpServletResponse servletResponse,
                        HttpServletRequest request) throws Exception{
        //1、根据微博回调给我们的code值,来换取accessToken,拿着这个accessToken我们可以换取到这个授权登录用户的信息
        Map<String,String> header = new HashMap<>();
        Map<String,String> query = new HashMap<>();
        Map<String,String> map = new HashMap<>();
        map.put("client_id","2636917288");
        map.put("client_secret","6a263e9284c6c1a74a62eadacc11b6e2");
        map.put("grant_type","authorization_code");
        map.put("redirect_uri","http://auth.toymail.com/oauth2.0/weibo/success");
        map.put("code",code);
        HttpResponse response = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", "post", header, query, map);

        // 2.获取响应结果,将微博返回给我们的用户信息转换为我们系统的真实用户
        if(response.getStatusLine().getStatusCode() == 200){
            //获取到了 accessToken
            String json = EntityUtils.toString(response.getEntity());
            WeiBoSocialUser boSocialUser = JSON.parseObject(json, WeiBoSocialUser.class);
            SocialUser socialUser = new SocialUser();
            socialUser.setBoSocialUser(boSocialUser);
            socialUser.setSourceType(MemberSocialUserEnum.WEIBO_LONGIN_USER.getCode());

            // 知道当前是哪个社交用户
            // 1）、当前用户如果是第一次进网站，自动注册进来(为当前社交用户生成一个会员信息账号，以后这个社交账号就对应指定的会员)
            // 登录或者注册这个社交用户
            R oauthLoginData = memberFeignService.oauthLogin(socialUser);
            if(oauthLoginData.getCode() == 0){
                MemberRespVo data = oauthLoginData.getData(new TypeReference<MemberRespVo>() {});
                log.info("登录成功：用户：{}",data.toString());
                // 获取用户成功,将当前用户在redis中存一份,然后重定向到商城首页
                session.setAttribute(AuthServerConstant.LOGIN_USER,data);
                return "redirect:http://toymail.com";
            }else {
                // 获取用户失败,重定向到认证服务重新登录
                return "redirect:http://auth.toymail.com/login.html";
            }

        }else {
            // 获取微博用户信息失败,重定向到认证服务重新登录
            return "redirect:http://auth.toymail.com/login.html";
        }

    }


    /**
     * @param
     * @==============History===============<br/>
     * @Description // 生成微信登录的二维码
     * @Date 2023/4/22 11:37
     * @Author <a href="qq:2277411582@qq.com">chen</a>
     * @return java.lang.String
     */
    @GetMapping("/wx/login")
    public String getWxCode(){
        // 1.微信开放平台授权baseUrl  %s相当于?代表占位符
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";

        // 2.对redirect_url进行URLEncoder编码,发送将来微信登录成功的回调地址
        String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
        try {
            redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
        }catch(Exception e) {

        }

        String url = String.format(
                baseUrl,
                ConstantWxUtils.WX_OPEN_APP_ID,
                redirectUrl,
                "atguigu"
        );


        // 4.重定向到请求微信地址里面
        return "redirect:"+url;
    }


    /**
     * @param code
 * @param state
     * @==============History===============<br/>
     * @Description // 处理微信登录成功的回调地址
     * @Date 2023/4/22 11:41
     * @Author <a href="qq:2277411582@qq.com">chen</a>
     * @return java.lang.String
     */
    @GetMapping("/api/ucenter/wx/callback")
    public String callback(String code, String state,HttpServletRequest request){
        try {
            // 1.获取code,临时票据,类似于验证码
            // 2.拿着code请求微信固定的地址，得到两个值 accsess_token 和 openid
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=%s" +
                    "&secret=%s" +
                    "&code=%s" +
                    "&grant_type=authorization_code";

            // 3.拼接三个参数 ：id  秘钥 和 code值
            String accessTokenUrl = String.format(
                    baseAccessTokenUrl,
                    ConstantWxUtils.WX_OPEN_APP_ID,
                    ConstantWxUtils.WX_OPEN_APP_SECRET,
                    code
            );

            // 4.请求这个拼接好的地址，得到返回两个值 accsess_token 和openid
            // 5.使用httpclient发送请求，得到返回结果
            String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
            HashMap mapAccessToken = JSON.parseObject(accessTokenInfo, HashMap.class);
            String access_token = (String) mapAccessToken.get("access_token");
            String openid = (String)mapAccessToken.get("openid");



            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=%s" +
                    "&openid=%s";
            // 拼接两个参数
            String userInfoUrl = String.format(
                    baseUserInfoUrl,
                    access_token,
                    openid
            );

            // 9.发送请求
            String userInfo = HttpClientUtils.get(userInfoUrl);
            // 10.获取返回userinfo字符串扫描人信息
            HashMap userInfoMap = JSON.parseObject(userInfo, HashMap.class);
            String nickname = (String)userInfoMap.get("nickname");//昵称
            String img = (String)userInfoMap.get("headimgurl");//头像

            // 7.把扫描人信息添加数据库里面
            // 8.判断数据表里面是否存在相同微信信息，根据openid(微信号)判断
            // 这里改一些,不管我们现在库里有没有这个微信用户,我们都去微信开放平台将这个微信用户的信息换回来
            SocialUser socialUser = new SocialUser();
            socialUser.setSourceType(MemberSocialUserEnum.WEI_XIN_LONGIN_USER.getCode());
            WeiXinSocialUser weiXinSocialUser = new WeiXinSocialUser(openid,nickname,img,access_token);
            socialUser.setXinSocialUser(weiXinSocialUser);
            R oauthLoginData = memberFeignService.oauthLogin(socialUser);
            if(oauthLoginData.getCode() == 0){
                // 这里有一个坑,微信登录回来session无法共享,我们去登录请求在把登录方法调用一边
                MemberRespVo data = oauthLoginData.getData(new TypeReference<MemberRespVo>() {});
                log.info("微信社交登录成功：用户：{}",data.toString());
//                // 获取用户成功,将当前用户在redis中存一份,然后重定向到商城首页
//                request.getSession().setAttribute(AuthServerConstant.LOGIN_USER,data);
                return "redirect:http://auth.toymail.com/weixinLonin?id="+data.getId();
            }else {
                // 获取用户失败,重定向到认证服务重新登录
                return "redirect:http://auth.toymail.com/login.html";
            }

        }catch (Exception e){
            e.printStackTrace();
            log.error("微信社交登录失败");
            return "redirect:http://auth.toymail.com/login.html";
        }
    }

}
